<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>js 作用域和闭包</title>
</head>
<body>

<div>
    <button onclick="forVarCallBackProblem()">传统的 在 for 循环中 使用 var 会导致的问题</button>
    <br>
    <button onclick="iifeSaveScopeFields()">使用IIFE为循环中的每一个回调函数创建一个临时作用域，作用域中保存当时变量的快照</button>
    <br>
    <button onclick="letBuildScopeFields()">使用let限定作用域</button>
</div>

<script type="application/javascript">

    /**
     * 传统的  在 for 循环中 使用 var 会导致的问题
     */
    function forVarCallBackProblem() {

        for (var i = 1; i < 10; i++) {
            /**
             * 因为使用的是 var 关键字，所有的 回调函数 对 for 循环作用域的引用都是共享的
             *
             * */
            setTimeout(() => {
                console.log("回调引用循环中的var闭包， i =", i) // 回调中的 i 都是共享的 ， 即 输出了10次 i = 10
            }, i * 1000)
        }

    }

    /**
     * 使用IIFE为循环中的每一个回调函数创建一个临时作用域，作用域中保存当时变量的快照
     */
    function iifeSaveScopeFields() {
        for (var i = 1; i < 10; i++) {
            (function (count) {
                // 这里使用了 匿名函数作用域 中 的 count 来 对 var i 来做快照
                // 回调函数中持有这个作用域
                // var i 还是在所用 for 循环中共享同一个
                setTimeout(() => {
                    console.log("使用IIFE为循环中的每一个回调函数创建一个临时作用域", "作用域中保存当时变量的快照", count)
                }, i * 1000)
            })(i)

        }
    }

    /**
     * 使用let限定作用域
     * let声明，可以用来劫持块作用域，并且在这个块作用域中声明一个变量。
     * 本质上这是将一个块转换成一个可以被关闭的作用域。
     *
     * 这个行为指出变量在循环过程中不止被声明一次，每次迭代
     * 都会声明。随后的每个迭代都会使用上一个迭代结束时的值来初始化这个变量。
     */
    function letBuildScopeFields() {
        for (let i = 1; i < 10; i++) {
            setTimeout(() => {
                console.log("使用let限定作用域", i)
            }, i * 1000)
        }
    }


</script>


</body>
</html>
